// [AUTO_HEADER]

#ifndef MDBackupData_h
#define MDBackupData_h

#include <CoreFoundation/CoreFoundation.h>
#include "Helpers.h"

namespace MobileSyncInspect {

	class MDBackupException {
	public:
		MDBackupException()
		{
		}
	};
	
	class MDBackup {
	public:
		MDBackup(const string& path)
			: m_path(path)
			, m_dictionaryRoot(NULL)
		{
			CFURLPathStyle pathStyle;
			#ifdef WIN32
				pathStyle = kCFURLWindowsPathStyle;
			#else
				pathStyle = kCFURLPOSIXPathStyle;
			#endif
			
			CFStringRef pathString = CFStringCreateWithCString(NULL, m_path.c_str(), kCFStringEncodingUTF8);
			CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, pathString, pathStyle, FALSE);
			CFReadStreamRef readStream = CFReadStreamCreateWithFile(NULL, fileURL);
			
			CFReadStreamOpen(readStream);
			
			CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
			CFStringRef errorString = 0;
			CFPropertyListRef propertyList = CFPropertyListCreateFromStream(NULL, readStream, 0, kCFPropertyListMutableContainersAndLeaves, &format, &errorString);
			
			// cerr << "Read property list format: " << format << endl;
			if (errorString) {				
				// cerr << "Read error: " << CFStringHelper::S(errorString) << "!" << endl;
				CFRelease(errorString);
				CFReadStreamClose(readStream);
				CFRelease(readStream);
				CFRelease(fileURL);
				CFRelease(pathString);
				
				throw MDBackupException();
			}
			
			if (CFGetTypeID(propertyList) != CFDictionaryGetTypeID()) {
				cerr << "Not a dictionary" << endl;

				CFReadStreamClose(readStream);
				CFRelease(readStream);
				CFRelease(fileURL);
				CFRelease(pathString);
				
				throw MDBackupException();
			}
			
			m_dictionaryRoot = (CFMutableDictionaryRef)propertyList;
			
			CFReadStreamClose(readStream);
			CFRelease(readStream);
			CFRelease(fileURL);
			CFRelease(pathString);
		}
		
		~MDBackup()
		{
			CFRelease(m_dictionaryRoot);
		}
		
		const string path() const
		{
			return CFStringHelper::S((CFStringRef)CFDictionaryGetValue(m_dictionaryRoot, CFSTR("Path")));
		}
		
		const size_t dataLength() const
		{
			CFDataRef data = (CFDataRef)CFDictionaryGetValue(m_dictionaryRoot, CFSTR("Data"));
			return CFDataGetLength(data);
		}
		
		const void *dataBytes() const
		{
			CFDataRef data = (CFDataRef)CFDictionaryGetValue(m_dictionaryRoot, CFSTR("Data"));
			return CFDataGetBytePtr(data);
		}
		
		bool replaceDataContentAndSave(const string& path)
		{
			pair<char *, size_t> result = OVFileHelper::SlurpFile(path);
			if (!result.first) {
				return false;
			}
			
			CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)result.first, (CFIndex)result.second, NULL);			
			CFDictionarySetValue(m_dictionaryRoot, CFSTR("Data"), data);			
			CFRelease(data);

			CFURLPathStyle pathStyle;
			#ifdef WIN32
				pathStyle = kCFURLWindowsPathStyle;
			#else
				pathStyle = kCFURLPOSIXPathStyle;
			#endif
			
			CFStringRef pathString = CFStringCreateWithCString(NULL, m_path.c_str(), kCFStringEncodingUTF8);
			CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, pathString, pathStyle, FALSE);
			CFRelease(pathString);
			CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, fileURL);
			CFRelease(fileURL);
			
			if (!CFWriteStreamOpen(writeStream)) {
				CFRelease(writeStream);
				return false;
			}

			CFStringRef errorString = 0;
			CFPropertyListWriteToStream(m_dictionaryRoot, writeStream, kCFPropertyListBinaryFormat_v1_0, &errorString);
			
			if (errorString) {				
				CFRelease(errorString);
				CFWriteStreamClose(writeStream);
				CFRelease(writeStream);
				return false;
			}
			
			CFWriteStreamClose(writeStream);
			CFRelease(writeStream);
			return true;
		}
		
		
	protected:
		string m_path;
		CFMutableDictionaryRef m_dictionaryRoot;
		
		// date and other metadata here
	};    
};

#endif